﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Settings;
using System.IO;
using System.Data;
using Utils;
using System.Collections.Concurrent;
using System.Threading;
using System.Data.SqlClient;

namespace SMSROUTER.Business
{
    public partial class Log
    {
        private static ConcurrentQueue<Log> _LogQueue = new ConcurrentQueue<Log>();

        private static List<Log> DeQueue(int batchSize)
        {
            List<Log> retList = new List<Log>();
            while (retList.Count < batchSize && !_LogQueue.IsEmpty)
            {
                Log dequeuElement = null;
                _LogQueue.TryDequeue(out dequeuElement);
                if (dequeuElement != null) retList.Add(dequeuElement);
            }
            return retList;
        }
        
        public static void InsertLog(Exception ex, string logSource, string logType, int? cooperateID)
        {
            InsertLog(ex.Message, ex.StackTrace, (!string.IsNullOrWhiteSpace(logSource) ? logSource + " | " : "") + ex.Source, logType, cooperateID);
        }

        public static void InsertLog(string logMessage, string logTrace, string logSource, string logType, int? cooperateID)
        {
            Log log = new Log();
            log.LogSource = logSource;
            log.LogMessage = logMessage;
            log.LogTime = DateTime.Now;
            log.LogTrace = logTrace;
            log.LogType = logType;
            log.Status = true;
            log.CooperateID = cooperateID;
            _LogQueue.Enqueue(log);
        }

        public static void BulkInsert()
        {
            List<Log> logs = DeQueue(AppSetting.BatchSize);
            if (logs.Count > 0)
            {
                try
                {
                    //Cố gắng dequeu thêm dữ liệu để xử lý
                    if (logs.Count < AppSetting.BatchSize)
                    {
                        DateTime now = DateTime.Now;
                        while ((logs.Count < AppSetting.BatchSize) && (DateTime.Now - now < TimeSpan.FromMilliseconds(AppSetting.UpdateDataDuration)))
                        {
                            logs.AddRange(DeQueue(AppSetting.BatchSize));
                        }
                    }
                    DataAccess.BulkInsert<Log>(logs, "Logs");
                }
                catch
                {
                    try
                    {
                        Xml.WriteListToFile<Log>(logs, AppSetting.LogBackupFileName);
                    }
                    catch
                    {

                    }
                }

                // Insert sang Alert System
                if (AppSetting.AlertSystemConnected)
                {
                    try
                    {
                        List<Warning_Message> warningMessages = new List<Warning_Message>();
                        foreach (Log log in logs)
                        {
                            Warning_Message wm = new Warning_Message();
                            wm.Message = AppSetting.ApplicationName + "|" + log.LogSource + "|" + log.LogMessage;
                            if (wm.Message.Length > 1000) wm.Message = wm.Message.Remove(1000);
                            wm.Message_Guid = Guid.NewGuid();
                            wm.Message_Time = log.LogTime.HasValue ? log.LogTime.Value : DateTime.Now;
                            wm.Message_Trace = log.LogTrace;
                            wm.Status = false;
                            wm.WarningSystem = AppSetting.SystemID;
                            wm.WarningType = log.LogType;
                            warningMessages.Add(wm);
                        }
                        DataAccess.BulkInsert<Warning_Message>(warningMessages, "Warning_Message", AppSetting.GetAlertSystemConnection());
                    }
                    catch
                    {

                    }
                }
            }
        }

        public static void EnqueueXmlData()
        {
            try
            {
                string fileName = AppSetting.LogBackupFileName;
                if (System.IO.File.Exists(fileName))
                {
                    SqlConnection conn = AppSetting.GetConnection();
                    if (conn.State == ConnectionState.Open)
                    {
                        List<Log> listLog = Xml.ReadFromFileToList<Log>(fileName);
                        // Sau khi đọc file xml xong thì xóa file đi.
                        System.IO.File.Delete(fileName);

                        if (listLog != null && listLog.Count > 0)
                        {
                            foreach (Log item in listLog)
                            {
                                _LogQueue.Enqueue(item);
                            }
                        }
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public static List<Log> Paging(DBDataContext context, int currentPage, int pageSize, ref int totalRecord, DateTime? fromTime, DateTime? toTime)
        {
            var result = context.Logs.OrderByDescending(p => p.LogID).AsQueryable();
            if (fromTime != null)
                result = result.Where(p => p.LogTime >= fromTime);
            if (toTime != null)
                result = result.Where(p => p.LogTime < toTime.Value.AddDays(1));
            totalRecord = result.Count();
            return result
                    .Skip(((currentPage - 1) < 0 ? 0 : (currentPage - 1)) * pageSize)
                    .Take(pageSize)
                    .ToList();
        }

        public static void LogToTexts(string[] smsGuid, string[] result, string routerType)
        {
            try
            {
                using (StreamWriter stream = File.AppendText(GetRouterLogFilePath(DateTime.Now, routerType)))
                {
                    for (int i = 0; i < smsGuid.Count(); i++)
                    {
                        string stt = "";
                        try
                        {
                            stt = result[i];
                        }
                        catch (Exception)
                        {
                            stt = "result array is out of range";
                        }
                        string line = string.Format("Guid = {0}; Result = {1}.", smsGuid[i] ?? Guid.Empty.ToString(), stt);
                        stream.WriteLine(line);
                    }
                }
            }
            catch (Exception)
            {
                Thread.Sleep(1000);
            }
        }

        public static void LogToText(Guid? smsGuid, string result, string routerType)
        {
            try
            {
                string line = string.Format("Guid = {0}; Result = {1}.", smsGuid ?? Guid.Empty, result ?? "") + Environment.NewLine;
                File.AppendAllText(GetRouterLogFilePath(DateTime.Now, routerType), line);
            }
            catch (Exception)
            {
                Thread.Sleep(1000);
            }
        }

        public static string GetRouterLogFilePath(DateTime dateTime, string routerType)
        {
            string yearPath = routerType == AppSetting.RouterType.MOROUTER ? Path.Combine(AppSetting.MORouterLog_Path, dateTime.ToString("yyyy")) : Path.Combine(AppSetting.MTRouterLog_Path, dateTime.ToString("yyyy"));
            string montPath = Path.Combine(yearPath, dateTime.ToString("yyyy-MM"));
            string filePath = Path.Combine(montPath, dateTime.ToString("yyyy-MM-dd") + ".txt");
            if (!Directory.Exists(yearPath)) Directory.CreateDirectory(yearPath);
            if(!Directory.Exists(montPath)) Directory.CreateDirectory(montPath);
            return filePath;
        }
    }
}
